package com.lancoo.cvas.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Pair;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lancoo.cvas.entity.*;
import com.lancoo.cvas.mapper.*;
import com.lancoo.cvas.pojo.common.Deleted;
import com.lancoo.cvas.pojo.response.Scheme;
import com.lancoo.cvas.pojo.vo.GradeDto;
import com.lancoo.cvas.pojo.vo.PlanTeachingToStudent;
import com.lancoo.cvas.pojo.vo.StudentGroupClass;
import com.lancoo.cvas.service.*;
import com.lancoo.cvas.util.BatchInsert;
import com.lancoo.cvas.util.WeekUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@Slf4j
@Service("planTeachingService")
public class PlanTeachingServiceImpl extends ServiceImpl<PlanTeachingMapper, PlanTeaching> implements PlanTeachingService {

    @Resource
    private CourseService courseService;

    @Resource
    private PlanTeachingMapper planTeachingMapper;

    @Resource
    private PlanTeachingCourseSegmentService planTeachingCourseSegmentService;

    @Resource
    private PlanTeachingCourseSegmentMapper planTeachingCourseSegmentMapper;

    @Resource
    private PlanTeachingStudentService planTeachingStudentService;


    @Resource
    private PlanTeachingStudentMapper planTeachingStudentMapper;
    @Resource
    private TeachingClassService teachingClassService;

    @Resource
    private TeachingClassStudentMapper teachingClassStudentMapper;

    @Resource
    private PlanTeachingService planTeachingService;
    @Resource
    private TaskToGradeService taskToGradeService;
    @Resource
    private TaskInfoService taskInfoService;

    @Resource
    private StudentService studentService;

    @Resource
    private MajorService majorService;

    @Resource
    private TeachingClassMapper teachingClassMapper;
    @Resource
    private TeachingClassWeekMapper teachingClassWeekMapper;
    @Resource
    private TeachingClassTeacherMapper teachingClassTeacherMapper;
    @Resource
    private TeachingClassWeekService teachingClassWeekService;

    @Resource
    private TeachingClassStudentService teachingClassStudentService;
    @Resource
    private TeachingClassTeacherService teachingClassTeacherService;
    @Resource
    private ClassInfoMapper classInfoMapper;


    @Override
    public void syncEducational(Integer taskId, List<Scheme> schemeList, String schoolId, String term) {
        List<PlanTeaching> planTeachings = new ArrayList<>();

        List<PlanTeachingCourseSegment> planTeachingCourseSegments = new ArrayList<>();

        Set<Course> courses = new HashSet<>();
        Set<Segment> segments = new HashSet<>();
        List<PlanTeachingStudent> planTeachingStudents = new ArrayList<>();
        List<TaskToGrade> gradeList = taskToGradeService.lambdaQuery().eq(TaskToGrade::getDeleted, Deleted.NOT.getCode())
                .eq(TaskToGrade::getTaskId, taskId).list().stream().sorted(Comparator.comparing(TaskToGrade::getGradeName)).collect(Collectors.toList());
        List<GradeDto> collect = taskInfoService.getGrade(schoolId, term).stream().sorted(Comparator.comparing(GradeDto::getGradeName)).collect(Collectors.toList());
        GradeDto gradeDto = collect.get(0);
        List<Scheme> schemeListNew = new ArrayList<>();
        for (TaskToGrade grade : gradeList) {
            List<Scheme> temp = new ArrayList<>();
            String s = JSON.toJSONString(schemeList);
            temp = JSON.parseArray(s, Scheme.class);

            temp.forEach(o -> {
                o.setSchemeID(o.getSchemeID() + "-" + grade.getGradeName().substring(0, 4));
                o.setGradeID(grade.getGradeId());
                o.setGradeName(grade.getGradeName());
            });
            schemeListNew.addAll(temp);
        }
        for (Scheme scheme : schemeListNew) {

            //如果该教学计划存在课程，则置为true， 同步该条教学计划
            boolean isExist = false;
            //根据学期判断是否需要上该课
            for (Scheme.CourseListDTO plan : scheme.getCourseList()) {
                int openingTerm = WeekUtil.getOpeningTerm(term, scheme.getGradeName(), gradeDto.getGradeName());
                //判断开课学期是否包含该课程
                if (!plan.getTerms().contains(String.valueOf(openingTerm))) {
                    continue;
                }
                int flag = 0;
                //todo 过滤该学期课程环节
                if ("1".equals(plan.getPlanType())) {
                    Course course = new Course()
                            .setTaskId(taskId)
                            .setBaseCourseId(plan.getPlanID())
                            .setCourseName(plan.getCourseName())
                            .setCourseTypeId(plan.getPlanKindID())
                            .setCourseType(plan.getPlanKindName())
                            .setCourseNature(plan.getCourseProp())
                            .setMajorProp(plan.getMajorProp())
                            .setCourseCode(plan.getCourseCode())
                            .setSubjectId(plan.getSubjectID())
                            .setSubjectName(plan.getSubjectName())
                            .setCredit(plan.getCredit())
                            .setLectureHour(plan.getLectureHours())
                            .setExperimentalHour(plan.getExperimentHours())
                            .setComputerHour(plan.getOperationHours())
                            .setOtherHour(plan.getOtherHours())
                            .setIsEnable(0);
                    //修读性质 1必修 2选修 3必修选修

                    if (!courses.contains(course)) {
                        courses.add(course);
                    }
                    flag = 1;
                } else if ("2".equals(plan.getPlanType())) {
                    Segment segment = new Segment()
                            .setTaskId(taskId)
                            .setBaseSegmentId(plan.getPlanID())
                            .setSegmentName(plan.getCourseName())
                            .setSegmentCode(plan.getCourseCode())
                            .setSegmentTypeId(plan.getPlanKindID())
                            .setSegmentType(plan.getPlanKindName())
                            .setCredit(plan.getCredit())
                            .setWeekNum(plan.getTotalHour())
                            .setIsEnable(0);

                    if (!segments.contains(segment)) {
                        segments.add(segment);
                    }
                    flag = 2;
                }
                //添加课程环节中间表
                planTeachingCourseSegments.add(new PlanTeachingCourseSegment()
                        .setTaskId(taskId)
                        .setBaseTeachingPlanId(scheme.getSchemeID())
                        .setBaseCourseId(plan.getPlanID())
                        .setFlag(flag));
            }

            planTeachings.add(scheme.toPlanTeaching(taskId));

        }

        for (Scheme scheme : schemeList) {
            planTeachingStudents.addAll(scheme.toPlanTeachingStudent(taskId));
        }


        //插入、更新或删除教学计划
        this.syncPlanTeaching(taskId, planTeachings);
        this.syncPlanSegCou(taskId, planTeachingCourseSegments);
        this.syncPlanStudent(taskId, planTeachingStudents);

        courseService.syncCourse(taskId, courses);
        courseService.syncSegment(taskId, segments);
    }

    /**
     * 根据课程/环节id和修读性质获取教学计划学生
     *
     * @param flag
     * @param courseId
     * @param studyNature
     * @param campusId
     * @return
     */
    @Override
    public List<Student> getStudentNumByCourseAndNature(int flag, Long courseId, Integer studyNature, String campusId) {
        List<PlanTeaching> planTeachings = new ArrayList<>();
        //根据课程id获取开课计划
        if (flag == 1) {
            planTeachings = planTeachingMapper.getPlanTeachingByCourseId(courseId, studyNature, campusId);
        } else {
            planTeachings = planTeachingMapper.getPlanTeachingBySegmentId(courseId, studyNature, campusId);
        }
        if (CollUtil.isEmpty(planTeachings)) {
            log.warn("课程id：{},修读性质：{} 的课程没有对应的教学计划", courseId, studyNature);
            return new ArrayList<>();
        }

        //根据教学计划统计学生数量
        Integer taskId = planTeachings.get(0).getTaskId();
        List<String> baseTeachingPlanIds = planTeachings.stream().map(PlanTeaching::getBaseTeachingPlanId).collect(Collectors.toList());
        List<Student> studentByPlanId = planTeachingMapper.getStudentByPlanId(taskId, baseTeachingPlanIds)
                .stream().distinct().collect(Collectors.toList());

        return studentByPlanId;

    }

    @Override
    public List<StudentGroupClass> getStudentListByCourse(Integer flag, Long courseId, Integer studyNature, String campusId, boolean isDisplaySelected) {
        List<StudentGroupClass> studentGroupClassList = new ArrayList<>();
        List<Student> studentNumByCourseAndNature = this.getStudentNumByCourseAndNature(flag, courseId, studyNature, campusId);
        if (CollUtil.isEmpty(studentNumByCourseAndNature)) {
            return studentGroupClassList;
        }
        if (!isDisplaySelected) {
            //排除已经选择该课程的学生。先获取教学班再获取教学班学生
            List<Long> teachingClassIds = teachingClassService.lambdaQuery()
                    .eq(TeachingClass::getCourseId, courseId)
                    .eq(TeachingClass::getStudyNature, studyNature)
                    .eq(TeachingClass::getCampusId, campusId)
                    .eq(TeachingClass::getFlag, flag)
                    .eq(TeachingClass::getDeleted, Deleted.NOT.getCode())
                    .list()
                    .stream().map(TeachingClass::getTeachingClassId).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(teachingClassIds)) {
                List<Long> studentIds = teachingClassStudentMapper.selectList(new LambdaQueryWrapper<TeachingClassStudent>()
                        .eq(TeachingClassStudent::getDeleted, Deleted.NOT.getCode())
                        .in(TeachingClassStudent::getTeachingClassId, teachingClassIds))
                        .stream().map(TeachingClassStudent::getStudentId).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(studentIds)) {
                    studentNumByCourseAndNature.removeIf(a -> studentIds.contains(a.getStudentId()));
                }
            }
        }
        //根据班级名称分组
        Map<Pair<String, String>, List<Student>> listMap = studentNumByCourseAndNature.stream().collect(Collectors.groupingBy(p -> Pair.of(p.getClassId(), p.getClassName())));
        listMap.entrySet().forEach(o -> {
            StudentGroupClass studentGroupClass = new StudentGroupClass();
            studentGroupClass.setClassId(o.getKey().getKey());
            studentGroupClass.setClassName(o.getKey().getValue());
            studentGroupClass.setStudentList(o.getValue());
            studentGroupClassList.add(studentGroupClass);
        });
        return studentGroupClassList;
    }

    @Override
    public List<Student> getMinorStudentByCourseId(Long courseId) {
        //获取包含该课程的辅修教学计划
        List<Student> students = new ArrayList<>();
        List<PlanTeaching> planTeachings = planTeachingMapper.getPlanTeachingByCourseId(courseId, 2, null);
        if (CollUtil.isNotEmpty(planTeachings)) {
            Integer taskId = planTeachings.get(0).getTaskId();
            List<String> baseTeachingIds = planTeachings.stream().map(PlanTeaching::getBaseTeachingPlanId).collect(Collectors.toList());
            students = planTeachingMapper.getStudentByPlanId(taskId, baseTeachingIds);
        }
        return students;
    }

    @Override
    public List<PlanTeaching> getPlanTeachingByClass(Integer taskId, String classId) {

        //培养方案对应学生
        List<PlanTeachingToStudent> planTeachingToStudentList = planTeachingStudentMapper.selectPlanTeachingToStudentList(taskId, Deleted.NOT.getCode());

        //培养方案
        List<PlanTeaching> planTeachings = planTeachingService.lambdaQuery().eq(PlanTeaching::getTaskId, taskId)
                .eq(PlanTeaching::getDeleted, Deleted.NOT.getCode()).list();

        //通过行政班id进行筛选
        List<PlanTeachingToStudent> planTeachingToStudents = planTeachingToStudentList.stream()
                .filter(p -> p.getClassId().equals(classId)).collect(Collectors.toList());

        List<String> basePlanTeaching = planTeachingToStudents.stream().map(PlanTeachingToStudent::getBaseTeachingPlanId).distinct().collect(Collectors.toList());


        //获取对应培养方案
        List<PlanTeaching> pTeaching = planTeachings.stream()
                .filter(p -> basePlanTeaching.contains(p.getBaseTeachingPlanId()))
                .collect(Collectors.toList());

        return pTeaching;
    }

    @Override
    public List<PlanTeaching> getPlanTeachingByMajor(Integer taskId, String gradeId, Long majorId) {

        //通过专业，获取行政班，获取对应学生，获取对应培养方案
        List<PlanTeachingToStudent> planTeachingToStudentList = planTeachingStudentMapper.selectPlanTeachingToStudentList(taskId, Deleted.NOT.getCode());

        List<ClassInfo> classInfos = classInfoMapper.selectList(new LambdaQueryWrapper<ClassInfo>()
                .eq(ClassInfo::getTaskId, taskId)
                .like(ClassInfo::getMajorId, majorId)
                .eq(ClassInfo::getGradeId, gradeId));


        List<PlanTeaching> planTeachings = planTeachingService.lambdaQuery().eq(PlanTeaching::getTaskId, taskId)
                .eq(PlanTeaching::getDeleted, Deleted.NOT.getCode()).list();

        List<String> collect = classInfos.stream().map(ClassInfo::getClassId).collect(Collectors.toList());


        List<PlanTeachingToStudent> planTeachingToStudents = planTeachingToStudentList.stream()
                .filter(p -> collect.contains(p.getClassId())).collect(Collectors.toList());


        List<String> baseTeachingPlan = planTeachingToStudents.stream().map(PlanTeachingToStudent::getBaseTeachingPlanId).distinct().collect(Collectors.toList());


        List<PlanTeaching> planTeachingList = planTeachings.stream().filter(p -> baseTeachingPlan.contains(p.getBaseTeachingPlanId())).distinct().collect(Collectors.toList());


        return planTeachingList;
    }

    @Override
    public Boolean mixedClassByCourse(Integer taskId, List<Long> teachingClassIds) {


        //需要进行合班的班级
        List<TeachingClass> teachingClasses = teachingClassMapper.selectList(new LambdaQueryWrapper<TeachingClass>()
                .eq(TeachingClass::getTaskId, taskId).in(TeachingClass::getTeachingClassId, teachingClassIds));

        List<Long> deletedTeachingIds = teachingClasses.stream().map(TeachingClass::getTeachingClassId).distinct().collect(Collectors.toList());

        TeachingClass mergeInfo = new TeachingClass();
        if (CollUtil.isNotEmpty(teachingClasses)) {
            mergeInfo = teachingClasses.get(0);
        }

        List<TeachingClassStudent> teachingClassStudentList = teachingClassStudentMapper.selectList(new LambdaQueryWrapper<TeachingClassStudent>()
                .in(TeachingClassStudent::getTeachingClassId, teachingClassIds));

        List<TeachingClassWeek> teachingClassWeek = teachingClassWeekMapper.selectList(new LambdaQueryWrapper<TeachingClassWeek>()
                .eq(TeachingClassWeek::getTeachingClassId, mergeInfo.getTeachingClassId()));

        List<TeachingClassTeacher> teachingClassTeacher = teachingClassTeacherMapper.selectList(new LambdaQueryWrapper<TeachingClassTeacher>()
                .eq(TeachingClassTeacher::getTeachingClassId, mergeInfo.getTeachingClassId()));


        UUID uuid = UUID.randomUUID();
//        String classId = "";
//        String className = "";
        TeachingClass teachingClass = new TeachingClass();
        teachingClass.setTaskId(taskId);
//        List<String> classIds = teachingClasses.stream().map(TeachingClass::getClassId).collect(Collectors.toList());
//        if (CollUtil.isNotEmpty(classIds)) {
//            classId = String.join(",", classIds);
//        }
//        List<String> classNames = teachingClasses.stream().map(TeachingClass::getClassName).collect(Collectors.toList());
//        if (CollUtil.isNotEmpty(classNames)) {
//            className = String.join(",", className);
//        }
//        teachingClass.setClassId(classId);
//        teachingClass.setClassName(className);
        teachingClass.setTeachingClassName(mergeInfo.getTeachingClassName());
        teachingClass.setCourseId(mergeInfo.getCourseId());
        teachingClass.setCourseName(mergeInfo.getCourseName());
        teachingClass.setMajorId(mergeInfo.getMajorId());
        teachingClass.setMajorName(mergeInfo.getMajorName());
        int sum = teachingClasses.stream().mapToInt(TeachingClass::getClassNum).sum();
        teachingClass.setClassNum(sum);
        teachingClass.setGradeId(mergeInfo.getGradeId());
        teachingClass.setGradeName(mergeInfo.getGradeName());
        teachingClass.setTeachingClassType(mergeInfo.getTeachingClassType());
        teachingClass.setRoomId(mergeInfo.getRoomId());
        teachingClass.setFlag(mergeInfo.getFlag());
        teachingClass.setCampusId(mergeInfo.getCampusId());
        teachingClass.setCampusName(mergeInfo.getCampusName());
        teachingClass.setUniqueShiftSign(uuid.toString());
        teachingClass.setIsEnable(6);
        teachingClass.setState(teachingClass.getState());
        teachingClassService.save(teachingClass);


        // 添加teachingClassWeek

        List<TeachingClassWeek> teachingClassWeeks = new ArrayList<>();
        for (TeachingClassWeek tw : teachingClassWeek) {
            TeachingClassWeek tClassWeek = new TeachingClassWeek();
            tClassWeek.setTeachingClassId(teachingClass.getTeachingClassId());
            tClassWeek.setWeek(tw.getWeek());
            tClassWeek.setRoomId(tw.getRoomId());
            tClassWeek.setRoomType(tw.getRoomType());
            tClassWeek.setWeekNum(tw.getWeekNum());
            tClassWeek.setConnectSection(tw.getConnectSection());
            tClassWeek.setConnectNumber(tw.getConnectNumber());
            tClassWeek.setAssessmentId(tw.getAssessmentId());
            tClassWeek.setAssessmentName(tw.getAssessmentName());
            tClassWeek.setHourType(tw.getHourType());
            teachingClassWeeks.add(tClassWeek);
        }

        teachingClassWeekService.saveBatch(teachingClassWeeks);


        List<TeachingClassStudent> teachingClassStudents = new ArrayList<>();

        for (TeachingClassStudent student : teachingClassStudentList) {

            TeachingClassStudent teachingClassStudent = new TeachingClassStudent();
            teachingClassStudent.setTeachingClassId(teachingClass.getTeachingClassId());
            teachingClassStudent.setStudentId(student.getStudentId());
            teachingClassStudents.add(teachingClassStudent);
        }

        if (CollUtil.isNotEmpty(teachingClassStudents)) {
            teachingClassStudentService.saveBatch(teachingClassStudents);
        }


        TeachingClassTeacher teacher = new TeachingClassTeacher();
        if (CollUtil.isNotEmpty(teachingClassTeacher)) {
            TeachingClassTeacher teacher1 = teachingClassTeacher.get(0);
            teacher.setTeachingClassId(teachingClass.getTeachingClassId());
            teacher.setTeacherId(teacher1.getTeacherId());
            teacher.setTeacherId(teacher1.getTeacherId());
            teacher.setTeacherType(0);
            teachingClassTeacherService.save(teacher);
        }

        //删除之前数据
        teachingClassMapper.update(null, new LambdaUpdateWrapper<TeachingClass>()
                .eq(TeachingClass::getTaskId, taskId)
                .in(TeachingClass::getTeachingClassId, deletedTeachingIds)
                .set(TeachingClass::getDeleted, Deleted.YES.getCode()));


        teachingClassWeekMapper.update(null, new LambdaUpdateWrapper<TeachingClassWeek>().
                in(TeachingClassWeek::getTeachingClassId, deletedTeachingIds).set(TeachingClassWeek::getDeleted, Deleted.YES.getCode()));

        teachingClassTeacherMapper.update(null, new LambdaUpdateWrapper<TeachingClassTeacher>()
                .in(TeachingClassTeacher::getTeachingClassId, deletedTeachingIds)
                .set(TeachingClassTeacher::getDeleted, Deleted.YES.getCode()));

        teachingClassStudentMapper.update(null, new LambdaUpdateWrapper<TeachingClassStudent>()
                .in(TeachingClassStudent::getTeachingClassId, deletedTeachingIds)
                .set(TeachingClassStudent::getDeleted, Deleted.YES.getCode()));

        return true;
    }

    private void syncPlanStudent(Integer taskId, List<PlanTeachingStudent> syncPlanTeachingStudent) {
        if (CollUtil.isNotEmpty(syncPlanTeachingStudent)) {
            Map<String, String> studentMap = studentService.lambdaQuery().eq(Student::getTaskId, taskId)
                    .eq(Student::getDeleted, Deleted.NOT.getCode())
                    .list().stream()
                    .collect(Collectors.toMap(Student::getBaseStudentId, Student::getGradeName));

            //删除之前已经添加的记录
            planTeachingStudentService.lambdaUpdate()
                    .eq(PlanTeachingStudent::getTaskId, taskId).remove();

            syncPlanTeachingStudent.forEach(o -> {
                o.setBaseTeachingPlanId(studentMap.get(o.getBaseStudentId()) == null ? ""
                        : o.getBaseTeachingPlanId() + "-" + studentMap.get(o.getBaseStudentId()).substring(0, 4));
            });

            //批量插入教学班学生，大数据批量插入
            Consumer<List<PlanTeachingStudent>> studentConsumer = o -> planTeachingStudentMapper.addBatch(o);
            BatchInsert.batchSplitInsert(syncPlanTeachingStudent, studentConsumer);


            List<PlanTeachingStudent> planTeachingStudentList = planTeachingStudentMapper.selectList(new LambdaQueryWrapper<PlanTeachingStudent>());

            List<PlanTeachingStudent> deletedStudentList = planTeachingStudentList.stream().filter(p -> StringUtils.isBlank(p.getBaseTeachingPlanId()))
                    .collect(Collectors.toList());

            List<Long> deletedIds = deletedStudentList.stream().map(PlanTeachingStudent::getId).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(deletedIds)) {
                planTeachingStudentService.lambdaUpdate()
                        .in(PlanTeachingStudent::getId, deletedIds)
                        .remove();
            }

        }


    }

    private void syncPlanSegCou(Integer taskId, List<PlanTeachingCourseSegment> syncPlanCS) {

        if (CollUtil.isNotEmpty(syncPlanCS)) {


            planTeachingCourseSegmentService.lambdaUpdate()
                    .eq(PlanTeachingCourseSegment::getTaskId, taskId).remove();


            if (CollUtil.isNotEmpty(syncPlanCS)) {
                planTeachingCourseSegmentMapper.addBatch(syncPlanCS);
            }

        }

    }

    private void syncPlanTeaching(Integer taskId, List<PlanTeaching> syncPlanTeaching) {
        List<PlanTeaching> insertList = new ArrayList<>();
        //获取数据库教学计划
        List<PlanTeaching> planTeachingList = this.list(new LambdaQueryWrapper<PlanTeaching>().eq(PlanTeaching::getTaskId, taskId)
                .eq(PlanTeaching::getDeleted, 0));
        //同步未同步的课程
        for (PlanTeaching planTeaching : syncPlanTeaching) {
            if (!planTeachingList.contains(planTeaching)) {
                insertList.add(planTeaching);
            }
        }

        planTeachingList.removeAll(syncPlanTeaching);
        List<Long> deleteIds = planTeachingList.stream().map(PlanTeaching::getTeachingPlanId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(deleteIds)) {
            this.lambdaUpdate().in(PlanTeaching::getTeachingPlanId, deleteIds).set(PlanTeaching::getDeleted, 1).update();
        }

        if (CollUtil.isNotEmpty(insertList)) {
            planTeachingService.saveBatch(insertList);
        }
    }
}